#include <stdio.h>
#include "shmem.h"
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdbool.h>
#include "cJSON.h"
#include "msg_queue_peer.h"

#define SERVER_IP "192.168.31.198"
#define SERVER_PORT 8888
#define SIZE 1024
#define NAME "stm"

char buf[1024] = {0};
char control[1024] = {0};
double temp = 0;
double humi = 0;
int fan_state = 0;
int ld1_state = 0;
int ld3_state = 0;
int beep_state = 0;
int motor_state = 0;

struct data
{
    double tem;
    double hum;
};

typedef union equipment
{
    bool a;
    int b;
    double c;
} Equipment;

typedef struct shm_stm
{
    int key;
    char name[32];
    int type;
    Equipment val;
} Shm_Stm;

typedef struct message
{
    long mtype;
    char mtext[256];
} Message;

int acceptfd;
struct shm_param para;
char *addr;

// 定义互斥锁
pthread_mutex_t acceptfd_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t shm_mutex = PTHREAD_MUTEX_INITIALIZER;

// 封装发送指令的函数
void send_equipment_command(int acceptfd, const char *command, const char *chinese_name, const char *action)
{
    ssize_t send_ret = send(acceptfd, command, strlen(command), 0);
    if (send_ret == -1)
    {
        perror("send command error");
    }
    else
    {
        printf("%s已%s\n", chinese_name, action);
    }
}

// 处理控制指令的函数
void handle_command(int acceptfd, const char *command)
{
    if (strcmp(command, "FAN_ON") == 0)
    {
        send_equipment_command(acceptfd, "FAN_ON", "风扇", "打开");
    }
    else if (strcmp(command, "FAN_OFF") == 0)
    {
        send_equipment_command(acceptfd, "FAN_OFF", "风扇", "关闭");
    }
    else if (strcmp(command, "LD1_ON") == 0)
    {
        send_equipment_command(acceptfd, "LD1_ON", "LED1", "打开");
    }
    else if (strcmp(command, "LD1_OFF") == 0)
    {
        send_equipment_command(acceptfd, "LD1_OFF", "LED1", "关闭");
    }
    else if (strcmp(command, "LD3_ON") == 0)
    {
        send_equipment_command(acceptfd, "LD3_ON", "LED3", "打开");
    }
    else if (strcmp(command, "LD3_OFF") == 0)
    {
        send_equipment_command(acceptfd, "LD3_OFF", "LED3", "关闭");
    }
    else if (strcmp(command, "BEEP_ON") == 0)
    {
        send_equipment_command(acceptfd, "BEEP_ON", "BEEP", "打开");
    }
    else if (strcmp(command, "BEEP_OFF") == 0)
    {
        send_equipment_command(acceptfd, "BEEP_OFF", "BEEP", "关闭");
    }
    else if (strcmp(command, "MOTOR_ON") == 0)
    {
        send_equipment_command(acceptfd, "MOTOR_ON", "MOTOR", "打开");
    }
    else if (strcmp(command, "MOTOR_OFF") == 0)
    {
        send_equipment_command(acceptfd, "MOTOR_OFF", "MOTOR", "关闭");
    }
    else
    {
        printf("未知指令: %s\n", command);
    }
}

// 接收消息队列指令并发送给单片机的线程函数
void *receive_mq_command(void *arg)
{
    while (1)
    {
        if (msg_queue_recv(NAME, control, sizeof(control), 0, 0) < 0)
        {
            perror("msg_queue_recv error");
            break;
        }
        control[strcspn(control, "\n")] = 0; // 去除可能的换行符
        printf("control:%s\n", control);

        pthread_mutex_lock(&acceptfd_mutex);
        handle_command(acceptfd, control);
        pthread_mutex_unlock(&acceptfd_mutex);

        memset(control, 0, sizeof(control));
    }
    return NULL;
}

// 接收数据并上传线程函数
void *receive_data(void *arg)
{
    while (1)
    {
        pthread_mutex_lock(&acceptfd_mutex);
        int ret = recv(acceptfd, buf, 1024, 0);
        pthread_mutex_unlock(&acceptfd_mutex);
        if (ret == -1)
        {
            perror("recv error");
            break;
        }
        else if (ret == 0)
        {
            printf("client quit...\n");
            break;
        }
        else if (ret > 0)
        {
            printf("recv:%s\n", buf);
            int parsed_count = sscanf(buf, "temp:%.2lf/hum:%.2lf/fan:%d/ld1:%d/ld3:%d/beep:%d/motor:%d",
                                      &temp, &humi, &fan_state, &ld1_state, &ld3_state, &beep_state, &motor_state);
            if (parsed_count != 7)
            {
                printf("Failed to parse received data: %s\n", buf);
                memset(buf, 0, 1024);
                continue;
            }

            pthread_mutex_lock(&shm_mutex);
            struct data *p = (struct data *)addr;
            p->tem = temp;
            p->hum = humi;
            printf("temp:%.2f,humi:%.2f\n", p->tem, p->hum);
            printf("数据已上传\n");
            memset(buf, 0, 1024);
            Shm_Stm local_stm_data[] = {
                {1, "temperature", 3, {.c = temp}},
                {2, "humidity", 3, {.c = humi}},
                {3, "red_light", 1, {.b = ld1_state}},
                {4, "fire", 1, {.b = ld3_state}},
                {5, "fan", 1, {.b = fan_state}},
                {6, "window", 1, {.b = motor_state}},
                {7, "light", 1, {.b = ld1_state}},
                {8, "buzzer", 1, {.b = beep_state}}};
            int stmnum = sizeof(local_stm_data) / sizeof(local_stm_data[0]);
            // 计算所需空间
            size_t required_size = sizeof(int) + stmnum * sizeof(Shm_Stm);
            if (required_size > SIZE)
            {
                printf("Data size exceeds shared memory size\n");
                pthread_mutex_unlock(&shm_mutex);
                continue;
            }
            // 先将数据数量写入共享内存起始位置
            int *shm_stm_addr_int = (int *)addr;
            *shm_stm_addr_int = stmnum;
            // 再将数据写入共享内存后续位置
            Shm_Stm *shm_stm_addr_struct = (Shm_Stm *)(shm_stm_addr_int + 1);
            for (int i = 0; i < stmnum; i++)
            {
                shm_stm_addr_struct->key = local_stm_data[i].key;
                strncpy(shm_stm_addr_struct->name, local_stm_data[i].name, sizeof(shm_stm_addr_struct->name) - 1);
                shm_stm_addr_struct->name[sizeof(shm_stm_addr_struct->name) - 1] = '\0';
                shm_stm_addr_struct->type = local_stm_data[i].type;
                shm_stm_addr_struct->val = local_stm_data[i].val;
                shm_stm_addr_struct++;
            }
            pthread_mutex_unlock(&shm_mutex);
        }
    }
    return NULL;
}

// 发送指令线程函数
void *send_command(void *arg)
{
    while (1)
    {
        scanf("%s", control);
        pthread_mutex_lock(&acceptfd_mutex);
        handle_command(acceptfd, control);
        pthread_mutex_unlock(&acceptfd_mutex);
        memset(control, 0, sizeof(control));
    }
    return NULL;
}

int main(int argc, char *argv[])
{

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        perror("err.");
        return -1;
    }
    printf("sockfd:%d\n", sockfd);
    // 2.绑定IP+port
    int opt = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    struct sockaddr_in saddr;                     // 身份结构定义
    saddr.sin_family = AF_INET;                   // 填充第一成员变量--协议族
    saddr.sin_port = htons(SERVER_PORT);          // 填充端口号 8888
    saddr.sin_addr.s_addr = inet_addr(SERVER_IP); // 填充IP地址
    socklen_t addrlen = sizeof(saddr);
    if (bind(sockfd, (struct sockaddr *)&saddr, addrlen) == -1)
    {
        perror("err.");
        close(sockfd);
        return -1;
    }
    printf("bind ok\n");
    // 3.监听 将主动套接字变成被动套接字
    listen(sockfd, 6);
    printf("正在等待连接...\n");
    // 4.accept,生成新的套接字--用于通信,当没有连接可建立的时候，阻塞
    acceptfd = accept(sockfd, NULL, NULL);
    printf("连接已建立...\n");

    if (shm_init(&para, NAME, SIZE) < 0)
    {
        printf("shm init err\n");
        close(sockfd);
        return -1;
    }
    addr = (char *)shm_getaddr(&para);
    if (addr == NULL)
    {
        printf("shm get addr err\n");
        shm_del(&para);
        close(sockfd);
        return -1;
    }

    pthread_t recv_thread, send_thread, mq_thread;
    // 创建接收数据线程
    if (pthread_create(&recv_thread, NULL, receive_data, NULL) != 0)
    {
        perror("pthread_create receive_data error");
        close(sockfd);
        shm_del(&para);
        return -1;
    }
    // 创建发送指令线程
    if (pthread_create(&send_thread, NULL, send_command, NULL) != 0)
    {
        perror("pthread_create send_command error");
        close(sockfd);
        shm_del(&para);
        return -1;
    }
    // 创建接收消息队列指令线程
    if (pthread_create(&mq_thread, NULL, receive_mq_command, NULL) != 0)
    {
        perror("pthread_create receive_mq_command error");
        close(sockfd);
        shm_del(&para);
        return -1;
    }

    // 等待线程结束
    pthread_join(recv_thread, NULL);
    pthread_join(send_thread, NULL);
    pthread_join(mq_thread, NULL);

    close(sockfd);
    shm_del(&para);

    return 0;
}